/*
**	Command & Conquer Red Alert(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*********************************************************************************************** 
 *                                                                                             * 
 *                 Project Name : Westwood Keyboard Library                                    * 
 *                                                                                             * 
 *                    File Name : KEYBOARD.CPP                                                 * 
 *                                                                                             * 
 *                   Programmer : Philip W. Gorrow                                             * 
 *                                                                                             * 
 *                   Start Date : 10/16/95                                                     * 
 *                                                                                             * 
 *                  Last Update : October 17, 1995 [PWG]                                       * 
 *                                                                                             * 
 *---------------------------------------------------------------------------------------------* 
 * Functions:                                                                                  * 
 *   WWKeyboardClass::Put -- Logic to insert a key into the keybuffer]                         * 
 *   WWKeyboardClass::Get -- Logic to get a metakey from the buffer                            * 
 *   WWKeyboardClass::Check -- Checks to see if a key is in the buffer                         * 
 *   WWKeyboardClass::Put_Key_Message -- Translates and inserts wParam into Keyboard Buffer    * 
 *   WWKeyboardClass::Buff_Get -- Lowlevel function to get a key from key buffer               * 
 *   WWKeyboardClass::Get_Mouse_X -- Returns the mouses current x position in pixels           * 
 *   WWKeyboardClass::Get_Mouse_Y -- returns the mouses current y position in pixels           * 
 *   WWKeyboardClass::Get_Mouse_XY -- Returns the mouses x,y position via reference vars       * 
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "keyboard.h"

/*********************************************************************************************** 
 * WWKeyboardClass::WWKeyBoardClass -- Construction for Westwood Keyboard Class                * 
 *                                                                                             * 
 * INPUT:		none							                                                        *
 *                                                                                             * 
 * OUTPUT:     none							                                                        *
 *                                                                                             * 
 * HISTORY:                                                                                    * 
 *   10/16/1995 PWG : Created.                                                                 * 
 *=============================================================================================*/
WWKeyboardClass::WWKeyboardClass(void)
{
	//
	// Initialize the keyboard remap table for our system (note it would be bad if someone
	// switched keyboard modes after this happened.
	//
	memset(VKRemap, 0, 2048);
	memset(AsciiRemap, 0, 256);
	for (short lp = 1; lp < 255; lp ++) {
		int vk_key = VkKeyScan(lp);
		if (vk_key > 0 && vk_key < 2048) {
			AsciiRemap[vk_key] = lp;
			VKRemap[vk_key] 	 = vk_key & 0xFF;
		}
	}

	//
	// Build a remap table of the different keys which are affected by the caps lock and
	// the num lock.
	//
	memset(ToggleKeys, 0, 256);
	for (lp = 0; lp < 255; lp++ ) {
		if (isalpha(lp) && isupper(lp)) {
			ToggleKeys[lp] = 1;
		}
		if (lp >= VK_NUMPAD0 && lp <= VK_DIVIDE) {
			ToggleKeys[lp] = 2;
		}
	}

	//
	// Our buffer should start devoid of keys.
	//
	memset(Buffer, 0, 256);
	Head		= 0;
	Tail		= 0;

	//
	// There should be no starting queued mouse events for us to have to worry
	// about.
	//
	MouseQX	= 0;
	MouseQY	= 0;
}

/*********************************************************************************************** 
 * WWKeyboardClass::Buff_Get -- Lowlevel function to get a key from key buffer                 * 
 *                                                                                             * 
 * INPUT:		none                                                        						  *
 *                                                                                             * 
 * OUTPUT:     int		- the key value that was pulled from buffer (includes bits)				  *                                                                                * 
 *                                                                                             * 
 * WARNINGS:   If the key was a mouse event MouseQX and MouseQY will be updated                *
 *                                                                                             * 
 * HISTORY:                                                                                    * 
 *   10/17/1995 PWG : Created.                                                                 * 
 *=============================================================================================*/
int WWKeyboardClass::Buff_Get(void)
{
	while (!Check()) {}										// wait for key in buffer
	int 	temp		= Buffer[Head];						// get key out of the buffer
	int   newhead	= Head;									// save off head for manipulation
	if (Is_Mouse_Key(temp)) {								// if key is a mouse then
		MouseQX	= Buffer[Head+1];							//		get the x and y pos
		MouseQY	= Buffer[Head+2];							//		from the buffer
		newhead += 3;		  									//		adjust head forward
	} else {
		newhead += 1;		  									//		adjust head forward
	}
	newhead	&= 255;
	Head		 = newhead;
	return(temp);
}

BOOL WWKeyboardClass::Is_Mouse_Key(int key)
{
	key &= 0xFF;
	return (key == VK_LBUTTON || key == VK_MBUTTON || key == VK_RBUTTON);
}


/*********************************************************************************************** 
 * WWKeyboardClass::Check -- Checks to see if a key is in the buffer                           * 
 *                                                                                             * 
 * INPUT:                                                                                      * 
 *                                                                                             * 
 * OUTPUT:                                                                                     * 
 *                                                                                             * 
 * WARNINGS:                                                                                   * 
 *                                                                                             * 
 * HISTORY:                                                                                    * 
 *   10/16/1995 PWG : Created.                                                                 * 
 *=============================================================================================*/
BOOL WWKeyboardClass::Check(void)
{
	unsigned short temp;											// store temp holding spot for key
	if (Head == Tail) return(FALSE);							// if no keys in buff then get out
	temp = Buffer[Head];											// get key out of the buffer
	return(temp);													// send it back to main program
}	

/*********************************************************************************************** 
 * WWKeyboardClass::Get -- Logic to get a metakey from the buffer                              * 
 *                                                                                             * 
 * INPUT:		none                                                        						  *
 *                                                                                             * 
 * OUTPUT:     int		- the meta key taken from the buffer.											  * 
 *                                                                                             * 
 * WARNINGS:	This routine will not return until a keypress is received							  *
 *                                                                                             * 
 * HISTORY:                                                                                    * 
 *   10/16/1995 PWG : Created.                                                                 * 
 *=============================================================================================*/
int WWKeyboardClass::Get(void)
{
	int temp,bits;										// store temp holding spot for key

	while (!Check()) {}								// wait for key in buffer
	temp = Buff_Get();								// get key from the buffer

	bits = temp & 0xFF00;							// save of keyboard bits
	
	if (!(bits & WWKEY_VK_BIT)) {					// if its not a virtual key
		temp = AsciiRemap[temp&0x1FF] | bits;	//   convert to ascii equivalent
	}
	return(temp);							// return the key that we pulled out
}	

/*********************************************************************************************** 
 * WWKeyboardClass::Put -- Logic to insert a key into the keybuffer]                           * 
 *                                                                                             * 
 * INPUT:		int	 	- the key to insert into the buffer          								  *
 *                                                                                             * 
 * OUTPUT:     bool		- true if key is sucessfuly inserted.							              *
 *                                                                                             * 
 * WARNINGS:   none							                                                        *
 *                                                                                             * 
 * HISTORY:                                                                                    * 
 *   10/16/1995 PWG : Created.                                                                 * 
 *=============================================================================================*/
BOOL WWKeyboardClass::Put(int key)
{
	int	temp		= (Tail + 1) & 255;
	if (temp != Head) 
	{
		Buffer[Tail]	= key;

		//
		// Critical Line
		//
		Tail				= temp;
		return(TRUE);
	}
	return(FALSE);
}
/*********************************************************************************************** 
 * WWKeyboardClass::Put_Key_Message -- Translates and inserts wParam into Keyboard Buffer      * 
 *                                                                                             * 
 * INPUT:                                                                                      * 
 *                                                                                             * 
 * OUTPUT:                                                                                     * 
 *                                                                                             * 
 * WARNINGS:                                                                                   * 
 *                                                                                             * 
 * HISTORY:                                                                                    * 
 *   10/16/1995 PWG : Created.                                                                 * 
 *=============================================================================================*/
WWKeyboardClass::Put_Key_Message(UINT vk_key, BOOL release, BOOL dbl)
{
	int bits = 0;
	//
	// Get the status of all of the different keyboard modifiers.  Note, only pay attention
	// to numlock and caps lock if we are dealing with a key that is affected by them.
	//
	int	shift		= (GetKeyState(VK_SHIFT) & 0xFF00) 		!= 0;
	int	ctrl 		= (GetKeyState(VK_CONTROL) & 0xFF00) 	!= 0;
	int	alt 		= (GetKeyState(VK_MENU) & 0xFF00) 		!= 0;
	int	caps		= ((GetKeyState(VK_CAPITAL) & 0x00FF) 	!= 0) && (ToggleKeys[vk_key] == 1);
	int	nums		= ((GetKeyState(VK_NUMLOCK) & 0x00FF) 	!= 0) && (ToggleKeys[vk_key] == 2);

	//
	// Set the proper bits for whatever the key we got is.
	//
	if (shift || caps || nums) {
		bits |= WWKEY_SHIFT_BIT;
	}
	if (ctrl) {
		bits |= WWKEY_CTRL_BIT;
	}
	if (alt) {
		bits |= WWKEY_ALT_BIT;
	}
	if (!AsciiRemap[vk_key|bits]) {
		bits |= WWKEY_VK_BIT;
	}
	if (release) {
		bits |= WWKEY_RLS_BIT;
	}
	if (dbl) {
		bits |= WWKEY_DBL_BIT;
	}
	//
	// Finally use the put command to enter the key into the keyboard
	// system.
	//
	return(Put(vk_key|bits));
}	

VOID WWKeyboardClass::Split(int &key, int &shift, int &ctrl, int &alt, int &rls, int &dbl)
{
	shift = (key & WWKEY_SHIFT_BIT)	!= 0;
	ctrl	= (key & WWKEY_CTRL_BIT)	!= 0;
	alt	= (key & WWKEY_ALT_BIT)		!= 0;
	rls	= (key & WWKEY_RLS_BIT)		!= 0;
	dbl	= (key & WWKEY_DBL_BIT)		!= 0;
	key	= (key & 0xFF);

}	

#pragma argsused
void WWKeyboardClass::Message_Handler(HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
	switch (message) {
		case WM_SYSKEYDOWN:
		case WM_KEYDOWN:
			Put_Key_Message(wParam);
			break;

		case WM_SYSKEYUP:
		case WM_KEYUP:
			Put_Key_Message(wParam, TRUE);
			break;

		case WM_LBUTTONDOWN:
			Put_Key_Message(VK_LBUTTON);
			Put(LOWORD(lParam));
			Put(HIWORD(lParam));
			break;

		case WM_LBUTTONUP:
			Put_Key_Message(VK_LBUTTON, TRUE);
			Put(LOWORD(lParam));
			Put(HIWORD(lParam));
			break;

		case WM_LBUTTONDBLCLK:
			Put_Key_Message(VK_LBUTTON, TRUE, TRUE);
			Put(LOWORD(lParam));
			Put(HIWORD(lParam));
			break;

		case WM_MBUTTONDOWN:
			Put_Key_Message(VK_MBUTTON);
			Put(LOWORD(lParam));
			Put(HIWORD(lParam));
			break;

		case WM_MBUTTONUP:
			Put_Key_Message(VK_MBUTTON, TRUE);
			Put(LOWORD(lParam));
			Put(HIWORD(lParam));
			break;

		case WM_MBUTTONDBLCLK:
			Put_Key_Message(VK_MBUTTON, TRUE, TRUE);
			Put(LOWORD(lParam));
			Put(HIWORD(lParam));
			break;

		case WM_RBUTTONDOWN:
			Put_Key_Message(VK_RBUTTON);
			Put(LOWORD(lParam));
			Put(HIWORD(lParam));
			break;

		case WM_RBUTTONUP:
			Put_Key_Message(VK_RBUTTON, TRUE);
			Put(LOWORD(lParam));
			Put(HIWORD(lParam));
			break;

		case WM_RBUTTONDBLCLK:
			Put_Key_Message(VK_RBUTTON, TRUE, TRUE);
			Put(LOWORD(lParam));
			Put(HIWORD(lParam));
			break;
	}
}	

/*********************************************************************************************** 
 * WWKeyboardClass::Get_Mouse_X -- Returns the mouses current x position in pixels             * 
 *                                                                                             * 
 * INPUT:		none                                                                            * 
 *                                                                                             * 
 * OUTPUT:     int		- returns the mouses current x position in pixels                      * 
 *                                                                                             * 
 * HISTORY:                                                                                    * 
 *   10/17/1995 PWG : Created.                                                                 * 
 *=============================================================================================*/
int WWKeyboardClass::Get_Mouse_X(void)
{
	POINT 	pt;
	GetCursorPos(&pt);
	return(pt.x);
}	
void WWKeyboardClass::Clear(void)
{
	Head = Tail;
}


/*********************************************************************************************** 
 * WWKeyboardClass::Get_Mouse_Y -- returns the mouses current y position in pixels             * 
 *                                                                                             * 
 * INPUT:		none                                                                            * 
 *                                                                                             * 
 * OUTPUT:     int		- returns the mouses current y position in pixels                      * 
 *                                                                                             * 
 * HISTORY:                                                                                    * 
 *   10/17/1995 PWG : Created.                                                                 * 
 *=============================================================================================*/
int WWKeyboardClass::Get_Mouse_Y(void)
{
	POINT 	pt;
	GetCursorPos(&pt);
	return(pt.y);
}	

/*********************************************************************************************** 
 * WWKeyboardClass::Get_Mouse_XY -- Returns the mouses x,y position via reference vars         * 
 *                                                                                             * 
 * INPUT:		int &x		- variable to return the mouses x position in pixels                *
 *					int &y		- variable to return the mouses y position in pixels					  *
 *                                                                                             * 
 * OUTPUT:     none - output is via reference variables                                        *
 *                                                                                             * 
 * HISTORY:                                                                                    * 
 *   10/17/1995 PWG : Created.                                                                 * 
 *=============================================================================================*/
void WWKeyboardClass::Get_Mouse_XY(int &x, int &y)
{
	POINT 	pt;

	GetCursorPos(&pt);
	x = pt.x;
	y = pt.y;
}	